home *** CD-ROM | disk | FTP | other *** search
/ PC World 2007 June / PCWorld_2007-06_cd.bin / v cisle / tclock / tclocklight-040702-3.exe / source / dll / startbtn.c < prev    next >
C/C++ Source or Header  |  2004-05-10  |  23KB  |  894 lines

  1. /*-------------------------------------------------------------
  2.   startbtn.c : customize start button
  3.   (C) 1997-2003 Kazuto Sato
  4.   Please read readme.txt about the license.
  5.   
  6.   Written by Kazubon, Nanashi-san
  7. ---------------------------------------------------------------*/
  8.  
  9. #include "tcdll.h"
  10. #include "newapi.h"
  11.  
  12. /* Globals */
  13.  
  14. void InitStartButton(HWND hwndClock);
  15. void ResetStartButton(HWND hwndClock);
  16. void EndStartButton(void);
  17. void ClearStartButtonResource(void);
  18. void CheckCursorOnStartButton(void);
  19. BOOL StartMenuFromClock(UINT message, WPARAM wParam, LPARAM lParam);
  20.  
  21. /* Statics */
  22.  
  23. static BOOL LoadStartButtonSetting(void);
  24. static BOOL SubClassStartButton(void);
  25. static void UnSubclassStartButton(void);
  26. static void InitStartButtonPos(HWND hwndClock);
  27. static void SetTaskWinPos(HWND hwndClock, HWND hwndStart, HWND hwndTask);
  28. static LRESULT CALLBACK WndProcStart(HWND, UINT, WPARAM, LPARAM);
  29. static LRESULT CALLBACK WndProcTask(HWND, UINT, WPARAM, LPARAM);
  30. static void SetStartButtonBmp(HWND hwnd);
  31. static void ReadStartButtonIcon(HWND hwnd,
  32.     HBITMAP* phbmp, HICON* phicon, const char* fname);
  33. static HFONT GetStartButtonFont(void);
  34. static void GetIconAndCaptionSize(SIZE *psz, HDC hdc,
  35.     HBITMAP hbmp, HICON hicon, const char* caption);
  36. static void DrawIconAndCaption(HDC hdc, HDC hdcMem, HBITMAP hbmp, HICON hicon,
  37.     const char* caption, int width, int height);
  38. void DrawStartButtonBack(HWND hwnd, HDC hdc, HDC hdcMem,
  39.     HBITMAP hbmpBack, int w, int h);
  40. static void OnDestroyStartButton(HWND hwnd);
  41. static void OnPaintButton(HWND hwnd, HDC hdc);
  42. static void DrawStartButtonFrame(HDC hdc, const RECT* prc,
  43.     BOOL bOver, BOOL bPushed);
  44.  
  45. static HWND m_hwndStart = NULL, m_hwndTask = NULL;
  46. static HWND m_hwndClock = NULL;
  47. static WNDPROC m_oldWndProcStart = NULL, m_oldWndProcTask = NULL;
  48. static BOOL m_bCustomize = FALSE;
  49. static BOOL m_bUseBackBmp = FALSE;
  50. static BOOL m_bFlat = FALSE;
  51. static BOOL m_bHide = FALSE;
  52. static BOOL m_bStartMenuClock = FALSE;
  53. static LONG m_oldClassStyle = 0;
  54. static BOOL m_bCursorOn = FALSE;
  55. static HBITMAP m_hbmpButton = NULL;
  56. static HDC m_hdcButton = NULL;
  57. static int m_wButton = -1, m_hButton = -1;
  58. static char *m_section = "StartButton";
  59.  
  60.  
  61. /*--------------------------------------------------
  62.   initialize
  63. ----------------------------------------------------*/
  64. void InitStartButton(HWND hwndClock)
  65. {
  66.     HWND hwndTaskbar, hwndTray;
  67.     
  68.     m_hwndClock = hwndClock;
  69.     
  70.     // find windows
  71.     
  72.     hwndTray = GetParent(hwndClock); // TrayNotifyWnd
  73.     if(hwndTray == NULL) return;
  74.     hwndTaskbar = GetParent(hwndTray); // Shell_TrayWnd
  75.     if(hwndTaskbar == NULL) return;
  76.     
  77.     // Start Button
  78.     m_hwndStart = FindWindowEx(hwndTaskbar, NULL, "Button", NULL);
  79.     
  80.     // Rebar
  81.     m_hwndTask = FindWindowEx(hwndTaskbar, NULL, "ReBarWindow32", NULL);
  82.     // Windows 95 without IE4
  83.     if(m_hwndTask == NULL)
  84.         m_hwndTask = FindWindowEx(hwndTaskbar, NULL, "MSTaskSwWClass", NULL);
  85.     
  86.     if(m_hwndStart == NULL || m_hwndTask == NULL)
  87.         return;
  88.     
  89.     if(!LoadStartButtonSetting())
  90.         return;
  91.     
  92.     if(m_bCustomize) SetStartButtonBmp(m_hwndStart);
  93.     
  94.     if(!SubClassStartButton())
  95.     {
  96.         ClearStartButtonResource();
  97.         return;
  98.     }
  99.     
  100.     InitStartButtonPos(hwndClock);
  101.     
  102.     SetTaskWinPos(hwndClock, m_hwndStart, m_hwndTask);
  103. }
  104.  
  105. /*--------------------------------------------------
  106.   apply changes of settings
  107. ----------------------------------------------------*/
  108. void ResetStartButton(HWND hwndClock)
  109. {
  110.     BOOL bOld = (m_oldWndProcStart && m_oldWndProcTask);
  111.     
  112.     ClearStartButtonResource();
  113.     
  114.     LoadStartButtonSetting();
  115.     
  116.     if(m_bCustomize) SetStartButtonBmp(m_hwndStart);
  117.     
  118.     if(!bOld && (m_bHide || m_bCustomize))
  119.     {
  120.         if(!SubClassStartButton())
  121.         {
  122.             ClearStartButtonResource();
  123.             return;
  124.         }
  125.     }
  126.     else if(bOld && !(m_bHide || m_bCustomize))
  127.     {
  128.         UnSubclassStartButton();
  129.         return;
  130.     }
  131.     
  132.     InitStartButtonPos(hwndClock);
  133.     
  134.     SetTaskWinPos(hwndClock, m_hwndStart, m_hwndTask);
  135. }
  136.  
  137. /*--------------------------------------------------
  138.   clear up
  139. ----------------------------------------------------*/
  140. void EndStartButton(void)
  141. {
  142.     UnSubclassStartButton();
  143.     
  144.     ClearStartButtonResource();
  145. }
  146.  
  147. /*--------------------------------------------------
  148.   delete memory DC and BMP
  149. ----------------------------------------------------*/
  150. void ClearStartButtonResource(void)
  151. {
  152.     if(m_hdcButton) DeleteDC(m_hdcButton); m_hdcButton = NULL;
  153.     if(m_hbmpButton) DeleteObject(m_hbmpButton); m_hbmpButton = NULL;
  154. }
  155.  
  156. /*--------------------------------------------------
  157.   Cursor position checking.
  158.   called when clock window receive WM_TIMER.
  159. ----------------------------------------------------*/
  160. void CheckCursorOnStartButton(void)
  161. {
  162.     POINT pt;
  163.     RECT rc;
  164.     
  165.     if(m_hwndStart == NULL || m_bCustomize == FALSE) return;
  166.     
  167.     GetCursorPos(&pt);
  168.     GetWindowRect(m_hwndStart, &rc);
  169.     if(PtInRect(&rc, pt))
  170.     {
  171.         if(!m_bCursorOn)
  172.         {
  173.             m_bCursorOn = TRUE;
  174.             InvalidateRect(m_hwndStart, NULL, FALSE);
  175.         }
  176.     }
  177.     else
  178.     {
  179.         if(m_bCursorOn)
  180.         {
  181.             m_bCursorOn = FALSE;
  182.             InvalidateRect(m_hwndStart, NULL, FALSE);
  183.         }
  184.     }
  185. }
  186.  
  187. /*--------------------------------------------------
  188.   Start menu from clock
  189. ----------------------------------------------------*/
  190. BOOL StartMenuFromClock(UINT message, WPARAM wParam, LPARAM lParam)
  191. {
  192.     if(message == WM_LBUTTONDOWN && m_bStartMenuClock &&
  193.         m_hwndStart && IsWindow(m_hwndStart))
  194.     {
  195.         SetWindowPos(m_hwndStart, NULL, 0, 0, 0, 0,
  196.             SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE);
  197.         // startmenu
  198.         PostMessage(m_hwndStart, message, wParam, lParam);
  199.         return TRUE;
  200.     }
  201.     return FALSE;
  202. }
  203.  
  204. /*--------------------------------------------------
  205.   read settings
  206. ----------------------------------------------------*/
  207. BOOL LoadStartButtonSetting(void)
  208. {
  209.     m_bCustomize = GetMyRegLong(NULL, "StartButton", FALSE);
  210.     m_bCustomize = GetMyRegLong(m_section, "StartButton", m_bCustomize);
  211.     
  212.     m_bUseBackBmp = GetMyRegLong(m_section, "UseBackBmp", FALSE);
  213.     
  214.     m_bFlat = GetMyRegLong(NULL, "StartButtonFlat", FALSE);
  215.     m_bFlat = GetMyRegLong(m_section, "Flat", m_bFlat);
  216.     
  217.     m_bHide = GetMyRegLong(NULL, "StartButtonHide", FALSE);
  218.     m_bHide = GetMyRegLong(m_section, "Hide", m_bHide);
  219.     
  220.     if(m_bHide) m_bCustomize = FALSE;
  221.     
  222.     m_bStartMenuClock = GetMyRegLong(NULL, "StartMenuClock", FALSE);
  223.     m_bStartMenuClock = GetMyRegLong(m_section, "StartMenuClock",
  224.         m_bStartMenuClock);
  225.     
  226.     if(!m_bCustomize && !m_bHide) return FALSE;
  227.     return TRUE;
  228. }
  229.  
  230. /*----------------------------------------------------------
  231.   subclassify Start button and ReBarWindow32/MSTaskSwWClass
  232. ------------------------------------------------------------*/
  233. BOOL SubClassStartButton(void)
  234. {
  235.     if(m_hwndStart == NULL || m_hwndTask == NULL) return FALSE;
  236.     
  237.     // check subclassification
  238.     if(IsSubclassed(m_hwndTask))
  239.         return FALSE;
  240.     
  241.     if(g_winver&WINXP)
  242.     {
  243.         m_oldClassStyle = GetClassLong(m_hwndStart, GCL_STYLE);
  244.         SetClassLong(m_hwndStart, GCL_STYLE,
  245.             m_oldClassStyle & ~(CS_HREDRAW|CS_VREDRAW));
  246.     }
  247.     
  248.     m_oldWndProcStart = (WNDPROC)GetWindowLong(m_hwndStart, GWL_WNDPROC);
  249.     SetWindowLong(m_hwndStart, GWL_WNDPROC, (LONG)WndProcStart);
  250.     m_oldWndProcTask = (WNDPROC)GetWindowLong(m_hwndTask, GWL_WNDPROC);
  251.     SetWindowLong(m_hwndTask, GWL_WNDPROC, (LONG)WndProcTask);
  252.     
  253.     return TRUE;
  254. }
  255.  
  256. /*----------------------------------------------------------
  257.   restore window procedures
  258. ------------------------------------------------------------*/
  259. void UnSubclassStartButton(void)
  260. {
  261.     if(m_hwndStart && IsWindow(m_hwndStart) && m_oldWndProcStart)
  262.     {
  263.         if(g_winver&WINXP)
  264.             SetClassLong(m_hwndStart, GCL_STYLE, m_oldClassStyle);
  265.         
  266.         SetWindowLong(m_hwndStart, GWL_WNDPROC, (LONG)m_oldWndProcStart);
  267.         
  268.         SetWindowPos(m_hwndStart, NULL, 0, 0, 0, 0,
  269.             SWP_NOSIZE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_SHOWWINDOW);
  270.     }
  271.     m_oldWndProcStart = NULL;
  272.     
  273.     if(m_hwndTask && IsWindow(m_hwndTask) && m_oldWndProcTask)
  274.     {
  275.         SetWindowLong(m_hwndTask, GWL_WNDPROC, (LONG)m_oldWndProcTask);
  276.     }
  277.     m_oldWndProcTask = NULL;
  278. }
  279.  
  280. /*----------------------------------------------------------
  281.   initialize size and position of Start button
  282. ------------------------------------------------------------*/
  283. void InitStartButtonPos(HWND hwndClock)
  284. {
  285.     HWND hwndTaskbar, hwndTray;
  286.     
  287.     hwndTray = GetParent(hwndClock);
  288.     hwndTaskbar = GetParent(hwndTray);
  289.     
  290.     if(m_bHide) // Hide Start Button
  291.     {
  292.         RECT rc; POINT pt;
  293.         m_wButton = 0; m_hButton = 0;
  294.         GetWindowRect(hwndTray, &rc);
  295.         pt.x = rc.left; pt.y = rc.top;
  296.         ScreenToClient(hwndTaskbar, &pt);
  297.         SetWindowPos(m_hwndStart, NULL, pt.x, pt.y,
  298.             rc.right - rc.left, rc.bottom - rc.top,
  299.             SWP_NOZORDER|SWP_NOACTIVATE|SWP_HIDEWINDOW);
  300.     }
  301.     else if(m_bCustomize)
  302.     {
  303.         SetWindowPos(m_hwndStart, NULL, 0, 0,
  304.             m_wButton, m_hButton,
  305.             SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE|SWP_SHOWWINDOW);
  306.     }
  307. }
  308.  
  309. /*------------------------------------------------------------
  310.   initalize size and position of ReBarWindow32/MSTaskSwWClass
  311. -------------------------------------------------------------*/
  312. void SetTaskWinPos(HWND hwndClock, HWND hwndStart, HWND hwndTask)
  313. {
  314.     RECT rcBar, rcTask, rcTray;
  315.     POINT pt;
  316.     int x, y, w, h;
  317.     
  318.     GetClientRect(GetParent(hwndStart), &rcBar);  // Shell_TrayWnd
  319.     GetWindowRect(GetParent(hwndClock), &rcTray); // TrayNotifyWnd
  320.     GetWindowRect(hwndTask, &rcTask);     // ReBarWindow32/MSTaskSwWClass
  321.     
  322.     pt.x = rcTask.left; pt.y = rcTask.top;
  323.     ScreenToClient(GetParent(hwndStart), &pt);
  324.     
  325.     x = pt.x; y = pt.y;
  326.     w = rcTask.right - rcTask.left;
  327.     h = rcTask.bottom - rcTask.top;
  328.     
  329.     // Taskbar is horizontal
  330.     if(rcBar.right > rcBar.bottom)
  331.     {
  332.         x = 2 + m_wButton;
  333.         w = rcTray.left - 2 - m_wButton - 2;
  334.         if(m_wButton > 0)
  335.         {
  336.             x += 2; w -= 2;
  337.         }
  338.     }
  339.     // Taskbar is vertical
  340.     else
  341.     {
  342.         y = 2 + m_hButton;
  343.         h = rcTray.top - 2 - m_hButton - 2;
  344.         if(m_hButton > 0)
  345.         {
  346.             y += 1; h -= 2;
  347.         }
  348.     }
  349.     SetWindowPos(hwndTask, NULL, x, y, w, h,
  350.         SWP_NOZORDER|SWP_NOACTIVATE);
  351. }
  352.  
  353. /*--------------------------------------------------
  354.   make offscreen DC and BMP
  355. ----------------------------------------------------*/
  356. void SetStartButtonBmp(HWND hwnd)
  357. {
  358.     char fname[MAX_PATH], s[MAX_PATH];
  359.     char caption[80];
  360.     HBITMAP hbmpIcon, hbmpBack;
  361.     HICON hIcon;
  362.     HDC hdc;
  363.     HFONT hfont, hfontOld;
  364.     COLORREF col;
  365.     
  366.     /* ---------- read settings and BMP file -------------- */
  367.     
  368.     hbmpIcon = NULL; hIcon = NULL;
  369.     
  370.     GetMyRegStr(NULL, "StartButtonIcon", s, MAX_PATH, "");
  371.     GetMyRegStr(m_section, "Icon", fname, MAX_PATH, s);
  372.     ReadStartButtonIcon(hwnd, &hbmpIcon, &hIcon, fname);
  373.     
  374.     GetMyRegStr(NULL, "StartButtonCaption", s, 80, "Start");
  375.     GetMyRegStr(m_section, "Caption", caption, 80, s);
  376.     
  377.     col = GetMyRegLong(m_section, "CaptionColor",
  378.         0x80000000 | COLOR_BTNTEXT);
  379.     if(col & 0x80000000) col = GetSysColor(col & 0x00ffffff);
  380.     
  381.     hbmpBack = NULL;
  382.     if(m_bUseBackBmp)
  383.     {
  384.         GetMyRegStr(m_section, "BackBmp", s, MAX_PATH, "");
  385.         RelToAbs(fname, s);
  386.         hbmpBack = ReadBitmap(hwnd, fname, TRUE);
  387.         if(!hbmpBack) m_bUseBackBmp = FALSE;
  388.     }
  389.     
  390.     /* ---------- offscreen DC -------------- */
  391.     
  392.     hdc = GetDC(hwnd);
  393.     m_hdcButton = CreateCompatibleDC(hdc); // offscreen DC
  394.     
  395.     SetBkMode(m_hdcButton, TRANSPARENT);
  396.     SetTextColor(m_hdcButton, col);
  397.     
  398.     hfont = NULL;
  399.     if(caption[0])
  400.     {
  401.         hfont = GetStartButtonFont();
  402.         if(hfont)
  403.             hfontOld = SelectObject(m_hdcButton, hfont);
  404.     }
  405.     
  406.     /* ---------- width and height of button -------------- */
  407.     
  408.     if(hbmpBack)
  409.     {
  410.         int w, h;
  411.         GetBmpSize(hbmpBack, &w, &h);
  412.         m_wButton = w;  m_hButton = h/3;
  413.     }
  414.     else
  415.     {
  416.         RECT rc;
  417.         SIZE sz;
  418.         
  419.         GetIconAndCaptionSize(&sz,
  420.             m_hdcButton, hbmpIcon, hIcon, caption);
  421.         
  422.         GetClientRect(GetParent(hwnd), &rc);
  423.         
  424.         m_wButton = sz.cx + 8;
  425.         if(m_wButton > 160) m_wButton = 160;
  426.         
  427.         if(IsXPVisualStyle()
  428.             && (rc.right - rc.left > rc.bottom - rc.top))
  429.         {
  430.             m_hButton = 30;
  431.             if(m_hButton > rc.bottom - rc.top)
  432.                 m_hButton = rc.bottom - rc.top;
  433.         }
  434.         else
  435.             m_hButton = GetSystemMetrics(SM_CYCAPTION) + 3;
  436.         if(sz.cy + 6 > m_hButton) m_hButton = sz.cy + 6;
  437.         if(m_hButton > 80) m_hButton = 80;
  438.     }
  439.     
  440.     /* ---------- offscreen BMP -------------- */
  441.     
  442.     m_hbmpButton = CreateCompatibleBitmap(hdc,
  443.         m_wButton, m_hButton*3);
  444.     SelectObject(m_hdcButton, m_hbmpButton);
  445.     
  446.     /* ---------- draw background -------------- */
  447.     
  448.     DrawStartButtonBack(hwnd, hdc, m_hdcButton,
  449.         hbmpBack, m_wButton, m_hButton);
  450.     
  451.     /* ---------- draw icon and caption -------------- */
  452.     
  453.     DrawIconAndCaption(hdc, m_hdcButton, hbmpIcon, hIcon, caption,
  454.         m_wButton, m_hButton);
  455.     
  456.     /* ---------- clean up -------------- */
  457.     
  458.     if(hfont)
  459.     {
  460.         SelectObject(m_hdcButton, hfontOld);
  461.         DeleteObject(hfont);
  462.     }
  463.     
  464.     if(hbmpBack) DeleteObject(hbmpBack);
  465.     if(hbmpIcon) DeleteObject(hbmpIcon);
  466.     if(hIcon)    DestroyIcon(hIcon);
  467.     
  468.     ReleaseDC(hwnd, hdc);
  469. }
  470.  
  471. /*--------------------------------------------------
  472.   read BMP / ICO / EXE file
  473. ----------------------------------------------------*/
  474. void ReadStartButtonIcon(HWND hwnd,
  475.     HBITMAP* phbmp, HICON* phicon, const char* fname)
  476. {
  477.     char fname2[MAX_PATH], fname3[MAX_PATH], head[2];
  478.     HFILE hf;
  479.     
  480.     *phbmp = NULL; *phicon = NULL;
  481.     if(fname[0] == 0) return;
  482.     
  483.     parse(fname2, fname, 0, MAX_PATH);
  484.     RelToAbs(fname3, fname2);
  485.     
  486.     hf = _lopen(fname3, OF_READ);
  487.     if(hf == HFILE_ERROR) return;
  488.     
  489.     _lread(hf, head, 2);
  490.     _lclose(hf);
  491.     
  492.     if(head[0] == 'B' && head[1] == 'M') // bitmap
  493.         *phbmp = ReadBitmap(hwnd, fname3, TRUE);
  494.     else if(head[0] == 'M' && head[1] == 'Z') // executable
  495.     {
  496.         char numstr[10];
  497.         HICON hiconl;
  498.         int n;
  499.         
  500.         parse(numstr, fname, 1, 10);
  501.         n = atoi(numstr);
  502.         if(ExtractIconEx(fname3, n, &hiconl, phicon, 1) < 2)
  503.             *phicon = NULL;
  504.         else DestroyIcon(hiconl);
  505.     }
  506.     else // icon
  507.     {
  508.         *phicon = (HICON)LoadImage(g_hInst, fname3,
  509.             IMAGE_ICON,
  510.             GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
  511.             LR_DEFAULTCOLOR|LR_LOADFROMFILE);
  512.     }
  513. }
  514.  
  515. /*--------------------------------------------------
  516.   create font of Start button
  517. ----------------------------------------------------*/
  518. HFONT GetStartButtonFont(void)
  519. {
  520.     char name[80];
  521.     int size, weight, italic;
  522.     
  523.     GetMyRegStr(m_section, "Font", name, 80, "");
  524.     
  525.     if(name[0] == 0)
  526.     {
  527.         HFONT hfont;
  528.         LOGFONT lf;
  529.         hfont = (HFONT)GetStockObject(DEFAULT_GUI_FONT);
  530.         if(hfont)
  531.         {
  532.             GetObject(hfont, sizeof(lf),(LPVOID)&lf);
  533.             strcpy(name, lf.lfFaceName);
  534.         }
  535.     }
  536.     
  537.     size = GetMyRegLong(m_section, "FontSize", 9);
  538.     if(size == 0) size = 9;
  539.     
  540.     weight = GetMyRegLong(m_section, "Bold", 0);
  541.     if(weight) weight = FW_BOLD;
  542.     else weight = 0;
  543.     italic = GetMyRegLong(m_section, "Italic", 0);
  544.     
  545.     return CreateMyFont(name, size, weight, italic, 0);
  546. }
  547.  
  548. /*--------------------------------------------------
  549.   calculate width and height of (icon + caption)
  550. ----------------------------------------------------*/
  551. void GetIconAndCaptionSize(SIZE *psz, HDC hdc,
  552.     HBITMAP hbmp, HICON hicon, const char* caption)
  553. {
  554.     TEXTMETRIC tm;
  555.     SIZE szCap;
  556.     int w, h;
  557.     
  558.     GetTextMetrics(hdc, &tm);
  559.     
  560.     w = 0; h = 0;
  561.     if(hbmp)
  562.         GetBmpSize(hbmp, &w, &h);
  563.     else if(hicon)
  564.     {
  565.         w = GetSystemMetrics(SM_CXSMICON);
  566.         h = GetSystemMetrics(SM_CYSMICON);
  567.     }
  568.     
  569.     szCap.cx = 0; szCap.cy = 0;
  570.     if(caption[0])
  571.     {
  572.         if(GetTextExtentPoint32(hdc,
  573.             caption, strlen(caption), &szCap) == 0)
  574.             szCap.cx = strlen(caption) * tm.tmAveCharWidth;
  575.     }
  576.     
  577.     psz->cx = w + 2 + szCap.cx;
  578.     psz->cy = (h > szCap.cy) ? h : szCap.cy;
  579. }
  580.  
  581. /*--------------------------------------------------
  582.   draw icon and caption on offscreen DC
  583. ----------------------------------------------------*/
  584. void DrawIconAndCaption(HDC hdc, HDC hdcMem, HBITMAP hbmp, HICON hicon,
  585.     const char* caption, int width, int height)
  586. {
  587.     SIZE sz;
  588.     TEXTMETRIC tm;
  589.     int w, h;
  590.     int i;
  591.     
  592.     GetTextMetrics(hdcMem, &tm);
  593.     
  594.     GetIconAndCaptionSize(&sz, hdcMem, hbmp, hicon, caption);
  595.     
  596.     w = 0; h = 0;
  597.     if(hbmp)
  598.         GetBmpSize(hbmp, &w, &h);
  599.     else if(hicon)
  600.     {
  601.         w = GetSystemMetrics(SM_CXSMICON);
  602.         h = GetSystemMetrics(SM_CYSMICON);
  603.     }
  604.     
  605.     for(i = 0; i < 3; i++)
  606.     {
  607.         int x, y, d;
  608.         
  609.         x = (width - sz.cx) / 2;
  610.         y = (height - h) / 2 + i * height;
  611.         
  612.         d = 0;
  613.         if(i == 2)
  614.         {
  615.             if(!m_bUseBackBmp) d = 1;
  616.         }
  617.         
  618.         if(hbmp)
  619.         {
  620.             HDC hdcTemp = CreateCompatibleDC(hdc);
  621.             SelectObject(hdcTemp, hbmp);
  622.             
  623.             if((g_winver&WIN98)||(g_winver&WIN2000))
  624.                 MyTransparentBlt(hdcMem, x + d, y + d, w, h,
  625.                     hdcTemp, 0, 0, w, h, GetSysColor(COLOR_3DFACE));
  626.             else
  627.                 BitBlt(hdcMem, x + d, y + d, w, h, hdcTemp, 0, 0, SRCCOPY);
  628.             
  629.             DeleteDC(hdcTemp);
  630.         }
  631.         else if(hicon)
  632.         {
  633.             DrawIconEx(hdcMem, x + d, y + d,
  634.                 hicon, w, h, 0, NULL, DI_NORMAL);
  635.         }
  636.         
  637.         if(caption)
  638.         {
  639.             x += w + 2;
  640.             y = (height - tm.tmHeight) / 2 + i * height;
  641.             
  642.             TextOut(hdcMem, x + d, y + d, caption, strlen(caption));
  643.         }
  644.     }
  645. }
  646.  
  647. /*--------------------------------------------------
  648.   draw background on offscreen DC
  649. ----------------------------------------------------*/
  650. void DrawStartButtonBack(HWND hwnd, HDC hdc, HDC hdcMem,
  651.     HBITMAP hbmpBack, int w, int h)
  652. {
  653.     RECT rc;
  654.     
  655.     if(IsXPVisualStyle())
  656.     {
  657.         int i;
  658.         for(i = 0; i < 3; i++)
  659.         {
  660.             CopyParentSurface(hwnd, hdcMem, 0, h*i, w, h, 0, 0);
  661.         }
  662.     }
  663.     else
  664.     {
  665.         HBRUSH hbr;
  666.         
  667.         SetRect(&rc, 0, 0, w, h*3);
  668.         hbr = CreateSolidBrush(GetSysColor(COLOR_3DFACE));
  669.         FillRect(hdcMem, &rc, hbr);
  670.         DeleteObject(hbr);
  671.         
  672.         if(!hbmpBack)
  673.         {
  674.             SetRect(&rc, 0, 0, w, h);
  675.             DrawStartButtonFrame(hdcMem, &rc, FALSE, FALSE);
  676.             SetRect(&rc, 0, h, w, h*2);
  677.             DrawStartButtonFrame(hdcMem, &rc, TRUE, FALSE);
  678.             SetRect(&rc, 0, h*2, w, h*3);
  679.             DrawStartButtonFrame(hdcMem, &rc, TRUE, TRUE);
  680.         }
  681.     }
  682.     
  683.     if(hbmpBack)
  684.     {
  685.         HDC hdcTemp = CreateCompatibleDC(hdc);
  686.         SelectObject(hdcTemp, hbmpBack);
  687.         
  688.         if((g_winver&WIN98)||(g_winver&WIN2000))
  689.             MyTransparentBlt(hdcMem, 0, 0, w, h*3,
  690.                 hdcTemp, 0, 0, w, h*3, GetSysColor(COLOR_3DFACE));
  691.         else BitBlt(hdcMem, 0, 0, w, h*3, hdcTemp, 0, 0, SRCCOPY);
  692.         
  693.         DeleteDC(hdcTemp);
  694.     }
  695. }
  696.  
  697. /*------------------------------------------------
  698.   subclass procedure of start button
  699. --------------------------------------------------*/
  700. LRESULT CALLBACK WndProcStart(HWND hwnd, UINT message,
  701.     WPARAM wParam, LPARAM lParam)
  702. {
  703.     switch(message)
  704.     {
  705.         case WM_SYSCOLORCHANGE:  // system setting is changed
  706.         case WM_WININICHANGE:
  707.             if(m_bCustomize)
  708.                 PostMessage(hwnd, WM_USER+10, 0, 0L);
  709.             return 0;
  710.         case (WM_USER + 10):     // re-create offscreen DC
  711.             if(m_bCustomize)
  712.             {
  713.                 ClearStartButtonResource();
  714.                 SetStartButtonBmp(hwnd);
  715.             }
  716.             return 0;
  717.         case WM_WINDOWPOSCHANGING:  // restrict button size
  718.         {
  719.             LPWINDOWPOS pwp;
  720.             pwp = (LPWINDOWPOS)lParam;
  721.             if(!(pwp->flags & SWP_NOSIZE))
  722.             {
  723.                 if(m_wButton > 0) pwp->cx = m_wButton;
  724.                 if(m_hButton > 0) pwp->cy = m_hButton;
  725.             }
  726.             if(m_bHide)
  727.             {
  728.                 RECT rc; POINT pt;
  729.                 GetWindowRect(GetParent(m_hwndClock), &rc); // TrayNotifyWnd
  730.                 pt.x = rc.left; pt.y = rc.top;
  731.                 ScreenToClient(GetParent(hwnd), &pt);  // Shell_TrayWnd
  732.                 pwp->x = pt.x; pwp->y = pt.y;
  733.                 pwp->cx = rc.right - rc.left;
  734.                 pwp->cy = rc.bottom - rc.top;
  735.             }
  736.             break;
  737.         }
  738.         case WM_SETTEXT:
  739.             return 0;
  740.         case WM_PAINT: // draw button
  741.         {
  742.             HDC hdc;
  743.             PAINTSTRUCT ps;
  744.             hdc = BeginPaint(hwnd, &ps);
  745.             OnPaintButton(hwnd, hdc);
  746.             EndPaint(hwnd, &ps);
  747.             return 0;
  748.         }
  749.         case BM_SETSTATE: // button status is changed
  750.         {
  751.             HDC hdc;
  752.             CallWindowProc(m_oldWndProcStart, hwnd, message, wParam, lParam);
  753.             hdc = GetDC(hwnd);
  754.             OnPaintButton(hwnd, hdc);
  755.             ReleaseDC(hwnd, hdc);
  756.             return 0;
  757.         }
  758.         case WM_KILLFOCUS:
  759.         case WM_SETFOCUS:
  760.             InvalidateRect(hwnd, NULL, FALSE);
  761.             return 0;
  762.         case WM_MOUSELEAVE:
  763.         case WM_MOUSEMOVE:
  764.             CheckCursorOnStartButton();
  765.             break;
  766.     }
  767.     
  768.     return CallWindowProc(m_oldWndProcStart, hwnd, message, wParam, lParam);
  769. }
  770.  
  771. /*--------------------------------------------------
  772.   subclass procedure of MSTaskSwWClass/ReBarWindow32
  773. ----------------------------------------------------*/
  774. LRESULT CALLBACK WndProcTask(HWND hwnd, UINT message,
  775.     WPARAM wParam, LPARAM lParam)
  776. {
  777.     switch(message)
  778.     {
  779.         case WM_WINDOWPOSCHANGING:  // restrict size and position
  780.         {
  781.             LPWINDOWPOS pwp;
  782.             RECT rcBar, rcTray;
  783.             
  784.             if(!m_hwndStart || !m_oldWndProcStart) break;
  785.             
  786.             if(!(m_bCustomize || m_bHide)) break;
  787.             
  788.             pwp = (LPWINDOWPOS)lParam;
  789.             
  790.             GetClientRect(GetParent(hwnd), &rcBar); // Shell_TrayWnd
  791.             if(!(m_hwndClock && IsWindow(m_hwndClock))) break;
  792.             GetWindowRect(GetParent(m_hwndClock), &rcTray); // TrayNotifyWnd
  793.             
  794.             // Taskbar is horizontal
  795.             if(rcBar.right > rcBar.bottom)
  796.             {
  797.                 pwp->x = 2 + m_wButton;
  798.                 pwp->cx = rcTray.left - 2 - m_wButton - 2;
  799.                 if(m_wButton > 0)
  800.                 {
  801.                     pwp->x += 2; pwp->cx -= 2;
  802.                 }
  803.             }
  804.             else // Taskbar is vertical
  805.             {
  806.                 if(rcTray.top < pwp->y)
  807.                 {
  808.                     pwp->cy = rcBar.bottom - 2 - m_hButton - 2;
  809.                 }
  810.                 else
  811.                 {
  812.                     pwp->cy = rcTray.top - 2 - m_hButton - 2;
  813.                 }
  814.                 pwp->y = 2 + m_hButton;
  815.                 if(m_hButton > 0)
  816.                 {
  817.                     pwp->y += 1; pwp->cy -= 2;
  818.                 }
  819.             }
  820.             break;
  821.         }
  822.     }
  823.     return CallWindowProc(m_oldWndProcTask, hwnd, message, wParam, lParam);
  824. }
  825.  
  826. /*--------------------------------------------------
  827.   start button drawing
  828. ----------------------------------------------------*/
  829. void OnPaintButton(HWND hwnd, HDC hdc)
  830. {
  831.     BOOL bPushed;
  832.     int y;
  833.     
  834.     if(!m_bCustomize || !m_hdcButton) return;
  835.     
  836.     bPushed = (SendMessage(hwnd, BM_GETSTATE, 0, 0) & BST_PUSHED)?1:0;
  837.     
  838.     if(bPushed) y = m_hButton * 2;
  839.     else if(m_bCursorOn && (m_bFlat || m_bUseBackBmp))
  840.         y = m_hButton;
  841.     else if(GetFocus() == hwnd) y = m_hButton;
  842.     else y = 0;
  843.     
  844.     BitBlt(hdc, 0, 0,
  845.         m_wButton, m_hButton, m_hdcButton, 0, y, SRCCOPY);
  846. }
  847.  
  848. /*--------------------------------------------------
  849.   draw frame of button
  850. ----------------------------------------------------*/
  851. void DrawStartButtonFrame(HDC hdc, const RECT* prc, BOOL bOver, BOOL bPushed)
  852. {
  853.     HPEN hpen, hpenold;
  854.     int color;
  855.     
  856.     if(!m_bFlat)
  857.     {
  858.         RECT rc;
  859.         CopyRect(&rc, prc);
  860.         DrawFrameControl(hdc, &rc, DFC_BUTTON,
  861.             bPushed ?
  862.                 (DFCS_BUTTONPUSH|DFCS_PUSHED) : (DFCS_BUTTONPUSH));
  863.         if(bOver && !bPushed)
  864.         {
  865.             InflateRect(&rc, -2, -2);
  866.             DrawFocusRect(hdc, &rc);
  867.         }
  868.         return;
  869.     }
  870.     
  871.     if(!bOver) return;
  872.     
  873.     color = GetSysColor(bPushed?COLOR_3DSHADOW:COLOR_3DHILIGHT);
  874.     hpen = CreatePen(PS_SOLID, 1, color);
  875.     hpenold = SelectObject(hdc, hpen);
  876.     MoveToEx(hdc, prc->left, prc->top, NULL);
  877.     LineTo(hdc, prc->right, prc->top);
  878.     MoveToEx(hdc, prc->left, prc->top, NULL);
  879.     LineTo(hdc, prc->left, prc->bottom);
  880.     SelectObject(hdc, hpenold);
  881.     DeleteObject(hpen);
  882.     
  883.     color = GetSysColor(bPushed?COLOR_3DHILIGHT:COLOR_3DSHADOW);
  884.     hpen = CreatePen(PS_SOLID, 1, color);
  885.     hpenold = SelectObject(hdc, hpen);
  886.     MoveToEx(hdc, prc->right-1, prc->top, NULL);
  887.     LineTo(hdc, prc->right-1, prc->bottom);
  888.     MoveToEx(hdc, prc->left, prc->bottom-1, NULL);
  889.     LineTo(hdc, prc->right, prc->bottom-1);
  890.     SelectObject(hdc, hpenold);
  891.     DeleteObject(hpen);
  892. }
  893.  
  894.